#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <errno.h>
#include <signal.h>

snd_pcm_t *capture = NULL;
char *buffer = NULL;
FILE *pcm_file = NULL;
volatile sig_atomic_t keep_recording = 1;

void handle_sigterm(int sig) {
    keep_recording = 0;
}

// 开始录音
snd_pcm_t* record_start(const char* name, snd_pcm_format_t format, unsigned int channel, unsigned int rate, snd_pcm_uframes_t* period) {
    snd_pcm_t *capture;
    snd_pcm_hw_params_t *params;
    int err;
    int dir;

    if ((err = snd_pcm_open(&capture, name, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
        fprintf(stderr, "Error opening PCM device %s: %s\n", name, snd_strerror(err));
        return NULL;
    }

    snd_pcm_hw_params_alloca(&params);
    snd_pcm_hw_params_any(capture, params);

    if ((err = snd_pcm_hw_params_set_access(capture, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        fprintf(stderr, "Error setting access: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    if ((err = snd_pcm_hw_params_set_format(capture, params, format)) < 0) {
        fprintf(stderr, "Error setting format: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    if ((err = snd_pcm_hw_params_set_channels(capture, params, channel)) < 0) {
        fprintf(stderr, "Error setting channels: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    if ((err = snd_pcm_hw_params_set_rate_near(capture, params, &rate, &dir)) < 0) {
        fprintf(stderr, "Error setting rate: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    printf("sample rate: %d Hz\n", rate);

    if ((err = snd_pcm_hw_params(capture, params)) < 0) {
        fprintf(stderr, "Error setting HW params: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }

    snd_pcm_hw_params_get_period_size(params, period, &dir);

    return capture;
}

int main() {
    snd_pcm_uframes_t period;
    int err;

    signal(SIGTERM, handle_sigterm);

    capture = record_start("hw:0,1", SND_PCM_FORMAT_S16_LE, 2, 44100, &period);
    if (!capture) {
        return 1;
    }

    printf("period: %lu frames\n", period);

    buffer = (char *) malloc(snd_pcm_frames_to_bytes(capture, period));
    if (!buffer) {
        perror("malloc");
        snd_pcm_close(capture);
        return 1;
    }

    pcm_file = fopen("output.pcm", "wb");
    if (!pcm_file) {
        perror("Error opening output file");
        free(buffer);
        snd_pcm_close(capture);
        return 1;
    }

    printf("Recording... Press the button again to stop.\n");
    while (keep_recording) {
        snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period);
        if (frames < 0) {
            fprintf(stderr, "Error from read: %s\n", snd_strerror(frames));
            if (frames == -EPIPE) {
                snd_pcm_prepare(capture);
            }
        }

        fwrite(buffer, snd_pcm_frames_to_bytes(capture, frames), 1, pcm_file);
    }

    // 清理资源
    free(buffer);
    fclose(pcm_file);
    snd_pcm_drain(capture);
    snd_pcm_close(capture);
    printf("Recording stopped.\n");

    return 0;
}